﻿using IdentityServer4.Models;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text.Json;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Configuration;
using IdentityServer4.Test;

namespace Identity.Server
{
    public static class SameSiteCookiesServiceCollectionExtensions
    {
        private const SameSiteMode Unspecified = SameSiteMode.Lax;

        public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.MinimumSameSitePolicy = Unspecified;
                options.OnAppendCookie = cookieContext =>
                    CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                options.OnDeleteCookie = cookieContext =>
                    CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
            });

            return services;
        }

        private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
        {
            if (options.SameSite == SameSiteMode.None)
            {
                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();

                if (DisallowsSameSiteNone(userAgent))
                {
                    options.SameSite = Unspecified;
                }
            }
        }

        private static bool DisallowsSameSiteNone(string userAgent)
        {
            if (userAgent.Contains("CPU iPhone OS 12")
                || userAgent.Contains("iPad; CPU OS 12"))
            {
                return true;
            }

            if (userAgent.Contains("Safari")
                && userAgent.Contains("Macintosh; Intel Mac OS X 10_14")
                && userAgent.Contains("Version/"))
            {
                return true;
            }

            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
            {
                return true;
            }

            return false;
        }
    }


    public static class StaticConfigService
    {
        private static IEnumerable<IdentityResource> IdentityResources =>
        [
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        ];

        public static void AddInitIdentityCofnig(this IServiceCollection services, ConfigurationManager configuration)
        {
        }

        public static void AddIdentityServerConfig(this IServiceCollection services)
        {
            var builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
                
                // 就是这里，自定义用户交互选项         
                options.UserInteraction = new UserInteractionOptions
                {
                    LoginUrl = "/login",//登录地址  
                    LogoutUrl = "/logout",//退出地址 
                    ConsentUrl = "/Account/Consent",//允许授权同意页面地址
                    ErrorUrl = "/Account/Error", //错误页面地址
                    LoginReturnUrlParameter = "ReturnUrl",//设置传递给登录页面的返回URL参数的名称。默认为returnUrl 
                    LogoutIdParameter = "logoutId", //设置传递给注销页面的注销消息ID参数的名称。缺省为logoutId 
                    ConsentReturnUrlParameter = "ReturnUrl", //设置传递给同意页面的返回URL参数的名称。默认为returnUrl
                    ErrorIdParameter = "errorId", //设置传递给错误页面的错误消息ID参数的名称。缺省为errorId
                    CustomRedirectReturnUrlParameter = "ReturnUrl", //设置从授权端点传递给自定义重定向的返回URL参数的名称。默认为returnUrl                   
                    CookieMessageThreshold = 5 //由于浏览器对Cookie的大小有限制，设置Cookies数量的限制，有效的保证了浏览器打开多个选项卡，一旦超出了Cookies限制就会清除以前的Cookies值
                };
            });
            // builder.AddClientCredentialsConfigService();
            // builder.AddPasswordConfigService();
            builder.AddCodeConfigService(services);
        }

        public static void AddClientCredentialsConfigService(this IIdentityServerBuilder builder)
        {
            builder.AddInMemoryIdentityResources(IdentityResources);
            builder.AddInMemoryApiScopes([
                new ApiScope("client_scope1"),
                new ApiScope("client_scope2")
            ]);
            builder.AddInMemoryApiResources([
                new ApiResource("api1", "api1") { Scopes = { "client_scope1", "client_scope2" } }
            ]);
            builder.AddInMemoryClients([
                new Client
                {
                    ClientId = "credentials_client",
                    ClientName = "Client Credentials Client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets =
                    {
                        new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256())
                    },
                    AllowedScopes = { "client_scope1", "client_scope2" }
                }
            ]);
            builder.AddDeveloperSigningCredential();
        }

        public static void AddPasswordConfigService(this IIdentityServerBuilder builder)
        {
            builder.AddTestUsers([
                new TestUser
                {
                    SubjectId = "1",
                    Username = "unitysir",
                    Password = "123456",
                    Claims =
                    {
                        new Claim(JwtClaimTypes.Name, "unitysir"),
                        new Claim(JwtClaimTypes.GivenName, "unitysir"),
                        new Claim(JwtClaimTypes.FamilyName, "unitysir"),
                        new Claim(JwtClaimTypes.Email, "unitysir@gmail.com"),
                        new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                        new Claim(JwtClaimTypes.WebSite, "http://unitysir.top"),
                        new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(new
                        {
                            street_address = "One Hacker Way",
                            locality = "Heidelberg",
                            postal_code = 69118,
                            country = "Germany"
                        }), IdentityServerConstants.ClaimValueTypes.Json)
                    }
                }
            ]);

            builder.AddInMemoryIdentityResources(IdentityResources);
            builder.AddInMemoryApiScopes([
                new ApiScope("pwd_scope1")
            ]);
            builder.AddInMemoryApiResources([
                new ApiResource("api1", "api1")
                {
                    Scopes = { "pwd_scope1" },
                    ApiSecrets = { new Secret("apipwd".Sha256()) } //api密钥
                }
            ]);
            builder.AddInMemoryClients([
                new Client
                {
                    ClientId = "password_client",
                    ClientName = "Resource Owner Password",

                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

                    AllowedScopes = { "pwd_scope1" }
                }
            ]);

            builder.AddDeveloperSigningCredential();
        }

        public static void AddCodeConfigService(this IIdentityServerBuilder builder, IServiceCollection services)
        {
            builder.AddTestUsers([
                new TestUser
                {
                    SubjectId = "1",
                    Username = "unitysir",
                    Password = "123456",
                    Claims =
                    {
                        new Claim(JwtClaimTypes.Name, "unitysir"),
                        new Claim(JwtClaimTypes.GivenName, "unitysir"),
                        new Claim(JwtClaimTypes.FamilyName, "unitysir"),
                        new Claim(JwtClaimTypes.Email, "unitysir@gmail.com"),
                        new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                        new Claim(JwtClaimTypes.WebSite, "http://unitysir.top"),
                        new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(new
                        {
                            street_address = "One Hacker Way",
                            locality = "Heidelberg",
                            postal_code = 69118,
                            country = "Germany"
                        }), IdentityServerConstants.ClaimValueTypes.Json)
                    }
                }
            ]);
            builder.AddInMemoryIdentityResources(IdentityResources);
            builder.AddInMemoryApiScopes([
                new ApiScope("code_scope1")
            ]);
            builder.AddInMemoryApiResources([
                new ApiResource("api1", "api1")
                {
                    Scopes = { "code_scope1" },
                    UserClaims = { JwtClaimTypes.Role }, //添加Cliam 角色类型
                    ApiSecrets = { new Secret("apipwd".Sha256()) }
                }
            ]);
            builder.AddInMemoryClients([
                new Client
                {
                    ClientId = "code_client",
                    ClientName = "code Auth",

                    AllowedGrantTypes = GrantTypes.Code,

                    RedirectUris =
                    {
                        "http://localhost:5095/signin-oidc", //跳转登录到的客户端的地址
                    },
                    PostLogoutRedirectUris =
                    {
                        "http://localhost:5095/signout-callback-oidc", //跳转登出到的客户端的地址
                    },
                    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        "code_scope1"
                    },
                    //允许将token通过浏览器传递
                    AllowAccessTokensViaBrowser = true,
                    // 是否需要同意授权 （默认是false）
                    RequireConsent = true
                }
            ]);
            builder.AddDeveloperSigningCredential();
            services.ConfigureNonBreakingSameSiteCookies();
        }
    }
}